#include "monitor.h"
#include "ui_monitor.h"
// 构造函数
Monitor::Monitor(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::Monitor)
{
    ui->setupUi(this);// 初始化UI
    // 按钮信号连接
    connect(ui->pushButtonOpen,SIGNAL(clicked()),this,SLOT(openMonitorSlot()));
    connect(ui->pushButtonPhoto,SIGNAL(clicked()),this,SLOT(screenshotSlot()));
    connect(ui->pushButtonSave,SIGNAL(clicked()),this,SLOT(photoSaveSlot()));
    connect(ui->pushButtonLast, SIGNAL(clicked()), this, SLOT(photoLastSlot()));
    connect(ui->pushButtonNext, SIGNAL(clicked()), this, SLOT(photoNextSlot()));
    // 初始化UDP套接字
    udpSocket = new QUdpSocket(this);
    if (!udpSocket->bind(QHostAddress::Any, 8777, QUdpSocket::ShareAddress))
    {
        qCritical() << "UDP Bind Failed:" << udpSocket->errorString();
        return;
    }
    // 信号连接
    connect(udpSocket, SIGNAL(readyRead()), this, SLOT(readPendingDatagrams()));

    // 定时器初始化（30ms触发一次）
    frameTimer = new QTimer(this);
    connect(frameTimer, SIGNAL(timeout()), this, SLOT(timerProcessVideoFrame(const QByteArray &frameData)));
    frameTimer->start(30); // 30ms处理一次
    isFrameStart = false;

    // 初始化请求数据
    datasend.clear();
    datasend.append("get_stream");// 发送流请求命令

    // 设置主机地址
    Monitor:: hostaddr.setAddress(host);
    if (udpSocket)
    {
        qDebug() << "send succese";
        udpSocket->writeDatagram(datasend.data(),  datasend.size(),hostaddr,port);
    }
    else
    {
        qDebug() << "udpSocket is not valid"; // 处理 udpSocket 无效的情况
    }

    // 加载人脸检测模型（路径需根据实际修改）

//    QString cascadePath = "D:/opencv/opencv3.4-install/install/etc/haarcascades/haarcascade_frontalface_alt2.xml";

    QString cascadePath = "D:/opencv/opencv3.4-install/install/etc/haarcascades/haarcascade_frontalface_alt2.xml";

    if(!faceCascade.load(cascadePath.toStdString())) {
        QMessageBox::critical(this, "错误", "无法加载人脸检测模型！");
        qDebug() << "模型路径：" << cascadePath;
    }
}

Monitor::~Monitor()
{
    delete ui;// 释放UI资源
    delete udpSocket;// 释放网络资源
    delete frameTimer;// 释放定时器
}

// 打开/关闭监控槽函数
void Monitor::openMonitorSlot()
{
    flag_lable = 1-flag_lable;// 切换标志位
    if(flag_lable)
    {
        qDebug()<<"打开监控";
        ui->pushButtonOpen->setText("关闭");
        ui->pushButtonSave->setEnabled(true);
    }
    else
    {
        qDebug()<<"关闭监控";
        ui->pushButtonOpen->setText("打开");
        ui->label->setText("请点击打开按钮！");

    }
}

// 设置截图保存路径
void Monitor::photoSaveSlot()
{

    //设置图片保存路径
    QMessageBox::StandardButton result =
            QMessageBox::question(this,"视频保存路径","请选择保存路径！");
    if(result == QMessageBox::Yes)
    {
        // 获取文件夹路径
        photosavepath = QFileDialog::getExistingDirectory(this,"保存图像","C:/");
        QFileInfo info(photosavepath);
        if(!info.isDir()) // 路径有效性检查
        {
            QMessageBox::warning(this,"提示",photosavepath.append("请检查文件！"));
            photosavepath.clear();
            return;
        }
        if(!info.isWritable())  // 写权限检查
        {
            QMessageBox::warning(this,"提示",photosavepath.append("请检查文件夹权限！"));
            photosavepath.clear();
            return;
        }
        //路径设置成功后使能其他按钮：截图 和相册上下切换
        ui->pushButtonPhoto->setEnabled(true);
        ui->pushButtonLast->setEnabled(true);
        ui->pushButtonNext->setEnabled(true);
        //显示保存路径
        ui->lineEdit->setText(photosavepath);
        ui->lineEdit->setStyleSheet("color: black;");
        //路径设置成功后加载图片列表
        loadPhotoList();
    }
    else if(result == QMessageBox::No)
    {
        QMessageBox::warning(this,"提示","未选择保存路径将无法截图！");
        return;
    }

}
// 截图功能实现
void Monitor::screenshotSlot()
{
    // 1. 校验输入数据
    if(currrentframeData.isEmpty()){
        QMessageBox::warning(NULL, "保存失败", "图像数据为空");
        return;
    }
    if(photosavepath.isEmpty()){
        QMessageBox::warning(NULL, "保存失败", "未选择保存路径");
        return;
    }
    // 2. 自动补充文件扩展名
    // 生成时间戳文件名（精确到秒）
    QString timestamp = QDateTime::currentDateTime().toString("yyyyMMdd_HHmmss");
    QString baseName = QString("%1/%2").arg(photosavepath).arg(timestamp);
    QString finalPath = baseName + ".jpg";
    // 处理文件重名（添加序号）
    QFileInfo checkFile(finalPath);
    int counter = 1;
    while(checkFile.exists()) {
        finalPath = QString("%1_%2.jpg").arg(baseName).arg(counter);
        checkFile.setFile(finalPath);
        counter++;
    }
    // 3. 创建并打开文件
    QFile file(finalPath);
    if(!file.open(QIODevice::WriteOnly)){
        QMessageBox::critical(NULL, "错误",
                              QString("无法创建文件：\n%1\n%2")
                              .arg(finalPath)
                              .arg(file.errorString()));
        return;
    }
    // 4. 写入数据
    qint64 bytesWritten = file.write(currrentframeData);
    file.close();
    // 5. 验证写入结果
    if(bytesWritten != currrentframeData.size())
    {
        QMessageBox::critical(NULL, "错误",
                              QString("文件写入不完整\n预期：%1字节\n实际：%2字节")
                              .arg(currrentframeData.size())
                              .arg(bytesWritten));
        QFile::remove(finalPath); // 删除不完整文件
        return;
    }
    QMessageBox::information(NULL, "成功",
                             QString("图像已保存至：\n%1")
                             .arg(QDir::toNativeSeparators(finalPath)));
    //完成截图并保存后重新加载图像列表
    loadPhotoList();
}

//UDP数据报处理
void Monitor::readPendingDatagrams()
{
    // 处理所有待接收的 UDP 数据报
    while (udpSocket->hasPendingDatagrams())
    {
        datagram.resize(udpSocket->pendingDatagramSize());// 调整缓冲区大小

        QHostAddress sender;
        quint16 senderPort;
        // 读取数据报内容及发送方地址
        udpSocket->readDatagram(datagram.data(), datagram.size(), &sender, &senderPort);

        // ***********************处理帧头**************************
        if (datagram.startsWith("MJPG") && datagram.size() >= 8)
        {
            // 解析帧头：前4字节为 "MJPG"，后4字节为帧大小（uint32_t）
            m_expectedSize = *reinterpret_cast<const uint32_t *>(datagram.constData() + 4);
            m_receivedSize = 0;
            videoBuffer.clear();
            videoBuffer.reserve(m_expectedSize);   // 预分配缓冲区空间
            continue;
        }
        // -------------------------- 数据分片处理 --------------------------
        // 收集帧数据
        if (m_expectedSize > 0)
        {
            int chunkSize = datagram.size();
            videoBuffer.append(datagram);  // 将分片追加到缓冲区
            m_receivedSize += chunkSize;

            // 强制处理事件保证流畅性   加了更卡，如果视频流出问题了可以改回来
            // QCoreApplication::processEvents(QEventLoop::AllEvents, 100);

            // 完整帧接收完成
            // 当接收到的数据达到预期大小时，处理完整帧
            if (m_receivedSize >= m_expectedSize)
            {
                // 清除已处理的数据，避免残留影响下一帧
                timerProcessVideoFrame(videoBuffer.left(m_expectedSize));
                videoBuffer.remove(0, m_expectedSize);  // 清除已处理的数据
                m_expectedSize = 0;
                m_receivedSize = 0;
            }
        }
    }
}
// 定时视频帧显示处理
void Monitor::timerProcessVideoFrame(const QByteArray &frameData)
{
    //QMutexLocker locker(&m_frameMutex);
    // 从字节数据加载 JPEG 图像

    if (image.loadFromData(frameData, "JPEG"))
    {
        currrentframeData = frameData;// 保存当前帧

        // ==== OpenCV人脸检测处理 ==
        if(isFaceDetectionEnabled)
        {
            // QImage转Mat
            cv::Mat cvImage(image.height(), image.width(), CV_8UC4,
                            (uchar*)image.bits(), image.bytesPerLine());

            // 转换颜色空间 BGR
            cv::cvtColor(cvImage, cvImage, cv::COLOR_RGBA2BGR);

            // 灰度化
            cv::Mat gray;
            cv::cvtColor(cvImage, gray, cv::COLOR_BGR2GRAY);
            cv::equalizeHist(gray, gray);

            // 人脸检测
            faceCascade.detectMultiScale(gray, faces, 1.1, 3, 0, cv::Size(80, 80));

            // 绘制矩形框
            for (const auto& face : faces)
            {
                cv::rectangle(cvImage, face, cv::Scalar(0, 0, 255), 3);
            }

            // Mat转QImage
            QImage tempImg(cvImage.data, cvImage.cols, cvImage.rows,
                           cvImage.step, QImage::Format_RGB888);
            image = tempImg.copy();
        }

        // 图像缩放处理
        QPixmap pixmap = QPixmap::fromImage(image.scaled(
                                                ui->label->size(),
                                                Qt::KeepAspectRatio,
                                                Qt::SmoothTransformation
                                                ));
        // 显示控制
        if(flag_lable)
        {
            ui->label->setPixmap(pixmap);
            ui->label->setAlignment(Qt::AlignCenter); // 居中对齐（若有空白区域）
        }
    }
    else
    {
        qDebug() << "Failed to load image from data";
        return;
    }
    //QMutexLocker unlock(&m_frameMutex);
}

//相册上一张
void Monitor::photoLastSlot()
{
    if(currentPhotoList.isEmpty()) return;
    // 循环切换（处理负数情况）
    currentPhotoIndex = (currentPhotoIndex - 1 + currentPhotoList.size()) % currentPhotoList.size();
    updatePhotoDisplay();
}

//相册上一张
void Monitor::photoNextSlot()
{
    if(currentPhotoList.isEmpty()) return;

    // 循环切换
    currentPhotoIndex = (currentPhotoIndex + 1) % currentPhotoList.size();
    updatePhotoDisplay();
}

// 加载图片列表
void Monitor::loadPhotoList()
{
    currentPhotoList.clear();
    currentPhotoIndex = -1;
    // 获取目录下所有图片文件（支持多种格式）
    QDir directory(photosavepath);
    QStringList filters = {"*.jpg", "*.jpeg", "*.png", "*.bmp"};
    currentPhotoList = directory.entryList(filters, QDir::Files);
    // 按文件名排序（时间戳命名自动按时间排序）
    currentPhotoList.sort();
    // 更新状态
    if(!currentPhotoList.isEmpty()){
        currentPhotoIndex = 0;
        updatePhotoDisplay();
        qDebug() << "发现图片数量:" << currentPhotoList.size();
    }
    else
    {
        QMessageBox::information(this, "提示", "相册目录中没有图片");
    }
}

//更新相册图片显示
void Monitor::updatePhotoDisplay()
{
    // 构建完整路径
    QString filePath = photosavepath + "/" + currentPhotoList.at(currentPhotoIndex);
    //再次确认文件是否存在
    QFileInfo checkFile(filePath);
    if(!checkFile.exists()){
        QMessageBox::warning(this, "错误", "图片文件已不存在");
        currentPhotoList.removeAt(currentPhotoIndex);
        loadPhotoList(); // 重新加载列表
        return;
    }
    // 加载并显示图片
    QPixmap pix(filePath);
    if(!pix.isNull())
    {
        // 缩放图片保持宽高比
        pix = pix.scaled(ui->labelPhoto->size(),
                         Qt::KeepAspectRatio,
                         Qt::SmoothTransformation);
        //显示在labelPhoto上
        ui->labelPhoto->setPixmap(pix);
        ui->labelPhoto->setAlignment(Qt::AlignCenter);
    }
    else
    {
        QMessageBox::warning(this, "错误", "无法加载图片文件");
    }
}





